/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.landery.modules.sinco.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import me.landery.modules.sinco.domain.Profit;
import me.landery.modules.sinco.domain.ProfitConfig;
import me.landery.modules.sinco.domain.Recommend;
import me.landery.modules.sinco.domain.em.ProfitType;
import me.landery.modules.sinco.domain.em.RewordType;
import me.landery.modules.sinco.repository.ProfitConfigRepository;
import me.landery.modules.sinco.service.RecommendService;
import me.landery.modules.sinco.service.VipService;
import me.landery.modules.sinco.service.dto.RecommendDto;
import me.landery.modules.sinco.service.dto.VipDto;
import me.landery.modules.sinco.service.mapstruct.VipMapper;
import me.landery.modules.system.domain.User;
import me.landery.modules.system.service.UserService;
import me.landery.modules.system.service.dto.UserDto;
import me.landery.modules.system.service.mapstruct.UserMapper;
import me.landery.utils.*;
import lombok.RequiredArgsConstructor;
import me.landery.modules.sinco.repository.ProfitRepository;
import me.landery.modules.sinco.service.ProfitService;
import me.landery.modules.sinco.service.dto.ProfitDto;
import me.landery.modules.sinco.service.dto.ProfitQueryCriteria;
import me.landery.modules.sinco.service.mapstruct.ProfitMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.security.interfaces.DSAPublicKey;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author landery
* @date 2022-06-23
**/
@Service
@RequiredArgsConstructor
public class ProfitServiceImpl implements ProfitService {

    private final ProfitRepository profitRepository;
    private final ProfitMapper profitMapper;

    private final UserService userService;
    private final UserMapper userMapper;

    private final RecommendService recommendService;

    private final ProfitConfigRepository profitConfigRepository;

    @Lazy
    @Autowired

    private final VipService vipService;
    private final VipMapper vipMapper;



    @Override
    public Map<String,Object> queryAll(ProfitQueryCriteria criteria, Pageable pageable){
        Page<Profit> page = profitRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(profitMapper::toDto));
    }

    @Override
    public List<ProfitDto> queryAll(ProfitQueryCriteria criteria){
        return profitMapper.toDto(profitRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public ProfitDto findById(Long id) {
        Profit profit = profitRepository.findById(id).orElseGet(Profit::new);
        ValidationUtil.isNull(profit.getId(),"Profit","id",id);
        return profitMapper.toDto(profit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProfitDto create(Profit resources) {
        return profitMapper.toDto(profitRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Profit resources) {
        Profit profit = profitRepository.findById(resources.getId()).orElseGet(Profit::new);
        ValidationUtil.isNull( profit.getId(),"Profit","id",resources.getId());
        profit.copy(resources);
        profitRepository.save(profit);
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            profitRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<ProfitDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (ProfitDto profit : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("推荐码id", profit.getRecommend().getId());
            map.put("收益类型", profit.getProfitConfig().getProfitContent());
            map.put("收益金额", profit.getProfit());
            map.put("创建日期", profit.getCreateTime());
            map.put("更新时间", profit.getUpdateTime());
            map.put("创建者", profit.getCreateBy());
            map.put("更新者", profit.getUpdateBy());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public JSONObject getMyProfit() {
        UserDto user = userService.findByName(SecurityUtils.getCurrentUsername());
        JSONObject jsonObject = new JSONObject();
        JSONArray jsonArray = new JSONArray();
        //获取推荐码
        RecommendDto recommendDto = recommendService.getReferCode();
        List<Map<String,Object>> alist = profitRepository.queryAllProfitByRid(recommendDto.getId());
        if (alist.size() <= 0) {
            jsonObject.put("allDaysProfit",jsonArray);
            return jsonObject;
        }

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        Date startDate = null;
        Date endDate = null;
        try {
            startDate = simpleDateFormat.parse(alist.get(0).get("date_time").toString());
            endDate = simpleDateFormat.parse(alist.get(alist.size() - 1).get("date_time").toString());
        }catch (ParseException e) {
            e.printStackTrace();
            throw new RuntimeException("日期格式错误");
        }
        //开始时间和结束时间不能为空
        if (startDate == null || endDate == null) {
            throw new RuntimeException("日期格式错误");
        }

        Calendar calendar = Calendar.getInstance();

        for(Date i = startDate; !i.after(endDate);){
            JSONObject tmpObject = new JSONObject();
            String i_date_str = simpleDateFormat.format(i);
            tmpObject.put("date_time",i_date_str);
            for (Map<String,Object> map : alist) {
                if (i_date_str.equals(map.get("date_time").toString())) {
                    tmpObject.put("totalProfit",map.get("totalProfit"));
                    break;
                }
            }
            //没有值得赋0
            if (!tmpObject.containsKey("totalProfit")){
                tmpObject.put("totalProfit",0.0);
            }

            jsonArray.add(tmpObject);
            //更新时间，往前加1
            calendar.setTime(i);
            calendar.add(Calendar.DATE, 1);
            i = calendar.getTime();
        }
        jsonObject.put("allDaysProfit",jsonArray);
        return jsonObject;
    }

    /**
     *
     * @param resources 用户信息，新用户信息
     * @param referCode 推荐码，用来获取老用户信息
     * @param type 收益类型，用来获取收益配置
     * @param totalPrice 收益金额，用来计算最终受益
     */
    @Override
    @Transactional
    public void doProfit(User resources, String referCode, ProfitType type, Double totalPrice) {
        //通过resource的用户名获取用户信息
        UserDto user = userService.findByName(resources.getUsername());

        //ifnewUserInvite
        //获取推荐码
        Recommend recommend = recommendService.getByReferCode(referCode);
        if (recommend == null) {
            throw new RuntimeException("邀请码不存在");
        }

        ProfitConfig profitConfig = profitConfigRepository.findByProfitType(type.getValue());
        if (profitConfig == null) {
            throw new RuntimeException("收益配置不存在");
        }
        //是否启用
        if (profitConfig.getStatus() != 1) {
            throw new RuntimeException("收益配置未启用");
        }
        //新建收益
        Profit profit = new Profit();
        profit.setUser(userMapper.toEntity(user));
        profit.setProfitConfig(profitConfig);
        profit.setRecommend(recommend);
        profit.setCost(totalPrice);
        //获取vip
        VipDto vipDto = vipService.findByUserID(recommend.getUser().getId());
        //判断收益类型
        if (Objects.equals(profitConfig.getRewordType(), RewordType.MONEY.getValue())){
            profit.setProfit(profitConfig.getReword());
            vipDto.setProfit(vipDto.getProfit() + profitConfig.getReword());
        }
        if (Objects.equals(profitConfig.getRewordType(), RewordType.PAY_PERCENT.getValue())){
            if (profitConfig.getReword() == null) {
                throw new RuntimeException("收益配置错误");
            }
            profit.setProfit(totalPrice * profitConfig.getReword());
            vipDto.setProfit(vipDto.getProfit() + profitConfig.getReword() * totalPrice);
        }
        if (Objects.equals(profitConfig.getRewordType(), RewordType.FREE_TIMES.getValue())){
            profit.setProfit(profitConfig.getReword());
            //给推荐人添加免费次数
            vipDto.setQuota(vipDto.getQuota() + Math.round(profitConfig.getReword()));
        }
        vipService.save(vipMapper.toEntity(vipDto));
        profitRepository.save(profit);

    }
}